﻿using CCManger.Common;
using CCManger.Common.Coder;
using CCManger.Common.Message;
using DotNetty.Codecs;
using DotNetty.Handlers.Logging;
using DotNetty.Handlers.Timeout;
using DotNetty.Handlers.Tls;
using DotNetty.Transport.Bootstrapping;
using DotNetty.Transport.Channels;
using DotNetty.Transport.Channels.Sockets;
using Serilog;
using System;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;

namespace CCManger.Client
{
    internal class Program
    {
        private static async Task RunClientAsync()
        {
            //ExampleHelper.SetConsoleLogger();

            var group = new MultithreadEventLoopGroup();

            X509Certificate2 cert = null;
            string targetHost = null;
            //if (ClientSettings.IsSsl)
            //{
            //    cert = new X509Certificate2(Path.Combine(ExampleHelper.ProcessDirectory, "dotnetty.com.pfx"), "password");
            //    targetHost = cert.GetNameInfo(X509NameType.DnsName, false);
            //}
            try
            {
                var bootstrap = new Bootstrap();
                bootstrap
                    .Group(group)
                    .Channel<TcpSocketChannel>()
                    .Option(ChannelOption.TcpNodelay, true)
                    .Handler(new ActionChannelInitializer<ISocketChannel>(channel =>
                    {
                        IChannelPipeline pipeline = channel.Pipeline;

                        if (cert != null)
                        {
                            pipeline.AddLast(new TlsHandler(stream => new SslStream(stream, true, (sender, certificate, chain, errors) => true), new ClientTlsSettings(targetHost)));
                        }

                        pipeline.AddLast(new LoggingHandler());
                        pipeline.AddLast(new DiscardClientHandler());
                    }));

                IChannel bootstrapChannel = await bootstrap.ConnectAsync(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 23456));

                Console.ReadLine();

                await bootstrapChannel.CloseAsync();
            }
            finally
            {
                group.ShutdownGracefullyAsync().Wait(1000);
            }
        }

        private static async Task RunClientAsync1()
        {
            //ExampleHelper.SetConsoleLogger();

            var group = new MultithreadEventLoopGroup();

            X509Certificate2 cert = null;
            string targetHost = null;
            //if (ClientSettings.IsSsl)
            //{
            //    cert = new X509Certificate2(Path.Combine(ExampleHelper.ProcessDirectory, "dotnetty.com.pfx"), "password");
            //    targetHost = cert.GetNameInfo(X509NameType.DnsName, false);
            //}
            try
            {
                var bootstrap = new Bootstrap();
                bootstrap
                    .Group(group)
                    .Channel<TcpSocketChannel>()
                    .Option(ChannelOption.TcpNodelay, true)
                    .Handler(new ActionChannelInitializer<ISocketChannel>(channel =>
                    {
                        IChannelPipeline pipeline = channel.Pipeline;

                        if (cert != null)
                        {
                            pipeline.AddLast("tls", new TlsHandler(stream => new SslStream(stream, true, (sender, certificate, chain, errors) => true), new ClientTlsSettings(targetHost)));
                        }
                        pipeline.AddLast(new LoggingHandler());
                        pipeline.AddLast("framing-enc", new LengthFieldPrepender(2));
                        pipeline.AddLast("framing-dec", new LengthFieldBasedFrameDecoder(ushort.MaxValue, 0, 2, 0, 2));

                        pipeline.AddLast("echo", new EchoClientHandler());
                    }));

                IChannel clientChannel = await bootstrap.ConnectAsync(new IPEndPoint(IPAddress.Parse(CCManagerHelper.ClientSettings.HostStr), CCManagerHelper.ClientSettings.Port));

                Console.ReadLine();

                await clientChannel.CloseAsync();
            }
            finally
            {
                await group.ShutdownGracefullyAsync(TimeSpan.FromMilliseconds(100), TimeSpan.FromSeconds(1));
            }
        }

        private static async Task MainRunClientAsync()
        {
            //ExampleHelper.SetConsoleLogger();

            var group = new MultithreadEventLoopGroup();

            X509Certificate2 cert = null;
            string targetHost = null;
            //if (ClientSettings.IsSsl)
            //{
            //    cert = new X509Certificate2(Path.Combine(ExampleHelper.ProcessDirectory, "dotnetty.com.pfx"), "password");
            //    targetHost = cert.GetNameInfo(X509NameType.DnsName, false);
            //}
            try
            {
                var bootstrap = new Bootstrap();
                bootstrap
                    .Group(group)
                    .Channel<TcpSocketChannel>()
                    .Option(ChannelOption.TcpNodelay, true)
                    .Handler(new ActionChannelInitializer<ISocketChannel>(channel =>
                    {
                        IChannelPipeline pipeline = channel.Pipeline;

                        if (cert != null)
                        {
                            pipeline.AddLast(new TlsHandler(stream => new SslStream(stream, true, (sender, certificate, chain, errors) => true), new ClientTlsSettings(targetHost)));
                        }
                        //配置编码解码器
                        pipeline.AddLast(new CommonEncoder<Common.Message.Message>());
                        pipeline.AddLast(new CommonDecoder());
                        // pipeline.AddLast(new LoggingHandler());
                        // IdleStateHandler 心跳 发送心跳
                        //客户端为写IDLE
                        pipeline.AddLast(new IdleStateHandler(0, 10, 0));//第一个参数为读，第二个为写，第三个为读写全部

                        HelloClientHandler ClientHandler = new HelloClientHandler
                        {
                            _Socket = pipeline.FirstContext()
                        };

                        ClientHandler.MessageReceived += ClientHandler_MessageReceived;
                        ClientHandler.MessageSend += ClientHandler_MessageSend;

                        pipeline.AddLast(ClientHandler);
                    }));

                IChannel bootstrapChannel = await bootstrap.ConnectAsync(new IPEndPoint(IPAddress.Parse(CCManagerHelper.ClientSettings.HostStr), CCManagerHelper.ClientSettings.Port));

                Console.ReadLine();

                await bootstrapChannel.CloseAsync();
            }
            catch (Exception ex)
            {
                Log.Error(ex, "错误");
            }
            finally
            {
                group.ShutdownGracefullyAsync().Wait(1000);
            }
        }

        /// <summary>
        /// 发送的消息
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private async static void ClientHandler_MessageSend(object sender, MessageEventArgs e)
        {
            try
            {
                var client = sender as HelloClientHandler;
                await Task.Run(() => { client.SendData(e.CMD); });
            }
            catch (Exception ex) { }
        }

        /// <summary>
        /// 接收到的信息
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private async static void ClientHandler_MessageReceived(object sender, MessageEventArgs e)
        {
            try
            {
                var client = sender as HelloClientHandler;
                await Task.Run(() =>
                {
                    switch (e.CMD.Command)
                    {
                        case COMMAND.Message:
                            Log.Debug($"Decoder方式，从服务端接收:{e.CMD.Content}");
                            return;

                        default:
                            return;
                    }
                });
            }
            catch (Exception ex)
            {
            }
        }

        private static void Main(string[] args)
        {
            CCManagerHelper.InitClientSerilog();
            Log.Information("客户端配置{@ClientSettings}", CCManagerHelper.ClientSettings);
            MainRunClientAsync().Wait();
            Console.ReadLine();
        }
    }
}